import os
import subprocess
import time
import webbrowser
import sys
import argparse

def preview_nerf_model(config_path):
    """预览 NeRF 模型"""
    if not os.path.exists(config_path):
        raise FileNotFoundError(f"配置文件不存在: {config_path}")
    
    print(f"准备预览模型: {config_path}")
    print("正在启动预览服务器...\n")

    os.environ["PYTHONUTF8"] = "1"
    if sys.stdout.encoding != "utf-8":
        sys.stdout.reconfigure(encoding="utf-8")

    preview_command = [
        "ns-viewer",
        "--load-config", config_path,
        "--viewer.websocket-port", "7007"
    ]

    try:
        process = subprocess.Popen(
            preview_command,
            stdout=subprocess.PIPE,
            stderr=subprocess.STDOUT,
            text=True,
            bufsize=0,
            shell=True,
            encoding="utf-8",
            errors="ignore"
        )

        print("预览服务器日志:")
        viewer_url = "http://localhost:7007"
        webbrowser.open(viewer_url)
        print(f"\n已尝试打开浏览器: {viewer_url}")
        print("若未加载，等待服务器启动后刷新页面\n")

        for line in process.stdout:
            try:
                print(line.strip())
            except UnicodeEncodeError:
                pass

        while True:
            time.sleep(1)

    except KeyboardInterrupt:
        print("\n正在关闭预览服务器...")
        process.terminate()
    except Exception as e:
        print(f"\n发生错误: {str(e)}")
        if 'process' in locals():
            process.terminate()

def export_nerf_model(config_path, output_dir=None, method="poisson"):
    """
    导出 NeRF 模型为 3D 格式
    支持的方法: poisson, tsdf, pointcloud
    """
    if not os.path.exists(config_path):
        raise FileNotFoundError(f"配置文件不存在: {config_path}")
    
    # 设置默认输出目录
    if output_dir is None:
        output_dir = os.path.join(os.path.dirname(config_path), "exported_model")
    
    os.makedirs(output_dir, exist_ok=True)
    
    print(f"开始导出模型: {config_path}")
    print(f"导出方法: {method}")
    print(f"输出目录: {output_dir}\n")
    
    # 构建导出命令
    export_command = [
        "ns-export",
        method,
        "--load-config", config_path,
        "--output-dir", output_dir
    ]
    
    try:
        process = subprocess.Popen(
            export_command,
            stdout=subprocess.PIPE,
            stderr=subprocess.STDOUT,
            text=True,
            bufsize=0,
            shell=True,
            encoding="utf-8"
        )
        
        print("导出进度:")
        for line in process.stdout:
            print(line.strip())
        
        # 等待导出完成
        process.wait()
        
        if process.returncode == 0:
            print("\n✅ 导出成功!")
            print(f"模型已保存到: {output_dir}")
            
            # 列出导出的文件
            exported_files = [f for f in os.listdir(output_dir) 
                            if f.endswith(('.obj', '.ply', '.glb', '.png'))]
            if exported_files:
                print("\n导出的文件:")
                for file in exported_files:
                    print(f" - {file}")
            
            # 在资源管理器中打开目录 (Windows)
            if sys.platform == "win32":
                os.startfile(output_dir)
            # MacOS
            elif sys.platform == "darwin":
                subprocess.Popen(["open", output_dir])
            # Linux
            else:
                subprocess.Popen(["xdg-open", output_dir])
        else:
            print("\n❌ 导出失败，请检查错误日志")
            
    except Exception as e:
        print(f"\n导出过程中发生错误: {str(e)}")

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="NeRF 模型预览和导出工具")
    parser.add_argument("config_path", help="模型配置文件路径")
    parser.add_argument("--export", action="store_true", help="执行模型导出")
    parser.add_argument("--method", default="poisson", 
                        choices=["poisson", "tsdf", "pointcloud"],
                        help="导出方法 (默认: poisson)")
    parser.add_argument("--output-dir", help="自定义输出目录")
    
    args = parser.parse_args()
    
    config_file_path = args.config_path
    
    if args.export:
        export_nerf_model(
            config_path=config_file_path,
            output_dir=args.output_dir,
            method=args.method
        )
    else:
        preview_nerf_model(config_file_path)